package com.sky.service.user.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.db.sql.Order;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.exception.BaseException;
import com.sky.mapper.CourierMapper;
import com.sky.mapper.MerchantMapper;
import com.sky.mapper.user.AddressBookMapper;
import com.sky.mapper.user.OrderDetailMapper;
import com.sky.mapper.user.OrderMapper;
import com.sky.mapper.user.ShoppingCartMapper;
import com.sky.pojo.*;
import com.sky.result.PageResult;
import com.sky.service.user.OrderService;
import com.sky.utils.MapUtils;
import com.sky.vo.*;
import com.sky.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private WebSocketServer webSocketServer;
    @Autowired
    private CourierMapper courierMapper;

    /**
     * 计算预计送达时间
     *
     * @param shopId
     * @param addr
     * @return
     */
    @Override
    public LocalDateTime getEstimatedDeliveryTime(Long shopId, String addr) {
        // 只需要查询菜品制作时间和配送时间即可
        Long time = shoppingCartMapper.getTime(BaseContext.getCurrentId());
        log.info("菜品制作时间:{}分", time);
        Merchant merchant = merchantMapper.queryById(shopId);
        Map<String, String> map = MapUtils.gaodeTwoPointCostDistanceAndTimeByAddress(merchant.getShopAddress(), addr);
        Long duration = Long.parseLong(map.get("duration"));
        log.info("配送耗时:{}秒", duration);
        Long costTime = time * 60 + duration + 600;
        return LocalDateTime.now().plusSeconds(costTime);
    }

    /**
     * 再来一单
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void oneMoreOrder(Long id) {
        Orders orders = orderMapper.queryById(id);
        if (orders == null) {
            log.info("未查询到订单");
            return;
        }
        orders.setCheckoutTime(null);
        orders.setOrderTime(LocalDateTime.now());
        orders.setNumber(UUID.randomUUID().toString());
        orderMapper.insert(orders);
        // 根据订单id查询订单详情列表
        List<OrderDetail> orderDetailList = orderDetailMapper.queryDishOrSetmealByOrderId(id);
        orderDetailList.forEach(orderDetail -> orderDetail.setOrderId(orders.getId()));
        orderDetailMapper.insertBatch(orderDetailList);
    }

    /**
     * 订单分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult pageQuery(OrdersPageQueryDTO dto) {
        dto.check();
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        Page<OrderVO> orderVOS = orderMapper.pageQuery(dto);
        orderVOS.forEach(orderVO -> {
            List<OrderDetail> orderDetailList = orderDetailMapper.queryDishOrSetmealByOrderId(orderVO.getId());
            orderVO.setOrderDetailList(orderDetailList);
            Long courierId = courierMapper.queryCourierByOrderNo(orderVO.getNumber());
            Courier courier = courierMapper.queryById(courierId);
            if (courier != null) {
                orderVO.setCourierTelephone(courier.getTelephone());
            }
            log.info("vo:{}", orderVO);
        });
        PageResult pageResult = new PageResult();
        pageResult.setRecords(orderVOS);
        pageResult.setTotal(orderVOS.getTotal());
        return pageResult;
    }

    /**
     * 各状态订单数量统计
     *
     * @return
     */
    @Override
    public OrderStatisticsVO orderStatusCount() {
        return orderMapper.orderStatusCount();
    }

    /**
     * 拒绝订单
     *
     * @param dto
     */
    @Override
    public void rejectOrder(OrdersRejectionDTO dto) {
        Orders orders = orderMapper.queryById(dto.getId());
        if (orders.getStatus() != 2) {
            // 不是处于待接单状态
            log.info("该状态下无法拒单");
            throw new BaseException("该状态无法拒单");
        }
        log.info("处于待接单状态,可以拒单");
        orders.setStatus(Orders.CANCELLED_ORDER);
        orders.setRejectionReason(dto.getRejectionReason());
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.modifyOrderStatus(orders);
    }

    /**
     * 提交订单
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderSubmitVO submit(OrdersSubmitDTO dto) {
        // 分布式锁,防止重复下单
        String key = "CREATE_USER:" + BaseContext.getCurrentId();
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "getKey", Duration.ofMinutes(10));
        if (!flag) {
            log.info("未获取到锁,禁止执行");
            throw new BaseException("重复下单");
        }
        log.info("获取到锁,准许执行");
        // 封装订单表数据
        Long time = shoppingCartMapper.getTime(BaseContext.getCurrentId());
        AddressBookVO addressBookVO = addressBookMapper.queryById(dto.getAddressBookId());
        List<ShoppingCart> shoppingCarts = shoppingCartMapper.queryList(BaseContext.getCurrentId());
        if (CollectionUtil.isEmpty(shoppingCarts)) {
            throw new BaseException("购物车无数据");
        }
        if (addressBookVO == null) {
            throw new BaseException("地址错误");
        }
        // 计算金额
        Double amount = 0.0;
        for (ShoppingCart shoppingCart : shoppingCarts) {
            amount += Double.parseDouble(shoppingCart.getNumber().toString()) * Double.parseDouble(shoppingCart.getAmount().toString());
        }
        Orders orders = new Orders();
        BeanUtils.copyProperties(dto, orders);
        orders.setNumber(UUID.randomUUID().toString());
        orders.setUserId(BaseContext.getCurrentId());
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setOrderTime(LocalDateTime.now());
        orders.setPayStatus(Orders.UN_PAID);
        orders.setAmount(BigDecimal.valueOf(amount).add(dto.getDeliveryFee()).add(BigDecimal.valueOf(dto.getPackAmount())));
        orders.setPhone(addressBookVO.getPhone());
        orders.setAddress(addressBookVO.getProvinceName() + addressBookVO.getCityName() + addressBookVO.getDistrictName() + addressBookVO.getDetail());
        orders.setMealTime(LocalDateTime.now().minusMinutes(time));
        orders.setConsignee(addressBookVO.getConsignee());
        orderMapper.insert(orders);
        // 封装订单详情数据
        List<OrderDetail> orderDetailList = new ArrayList<>();
        shoppingCarts.forEach(shoppingCart -> {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(shoppingCart, orderDetail);
            orderDetail.setOrderId(orders.getId());
            orderDetailList.add(orderDetail);
        });
        orderDetailMapper.insertBatch(orderDetailList);
        // 清空购物车
        shoppingCartMapper.cleanList(BaseContext.getCurrentId());
        // 返回数据
        OrderSubmitVO vo = OrderSubmitVO.builder().orderTime(orders.getOrderTime())
                .id(orders.getId())
                .orderAmount(orders.getAmount())
                .orderNumber(orders.getNumber())
                .build();
        return vo;
    }

    /**
     * 下单成功,通知前端
     *
     * @param num
     */
    @Override
    public void paySuccess(String num) {
        // 用户先下单成功,修改订单状态
        Orders orders = orderMapper.queryByNum(num);
        if (orders == null) {
            log.info("订单不存在");
            return;
        }
        orders.setStatus(Orders.TO_BE_CONFIRMED);
        orders.setPayStatus(Orders.PAID);
        orderMapper.modifyOrderStatus(orders);
        // 发送消息给前端
        Map<String, Object> map = new HashMap<>();
        map.put("type", 1);
        map.put("orderId", orders.getId());
        map.put("content", "有新订单,请及时处理");
        webSocketServer.sendToShop(JSON.toJSONString(map));
    }

    /**
     * 用户催单
     */
    @Override
    public void toCompleteOrderFast(String num) {
        Orders orders = orderMapper.queryByNum(num);
        if (orders == null) {
            log.info("订单不存在");
            return;
        }
        log.info("用户催单");
        // 发送消息给前端
        Map<String, Object> map = new HashMap<>();
        map.put("type", 2);
        map.put("orderId", orders.getId());
        map.put("content", "有用户催单了,请及时处理");
        webSocketServer.sendToShop(JSON.toJSONString(map));
    }

    /**
     * 查询历史订单
     *
     * @param dto
     * @return
     */
    @Override
    public PageResult queryHistoryOrders(HistoryPageDTO dto) {
        dto.check();
        PageHelper.startPage(dto.getPage(), dto.getPageSize());
        Long userId = BaseContext.getCurrentId();
        Page<Orders> orders = orderMapper.queryHistoryOrders(dto, userId);
        List<OrderVO> orderVOS = orders.stream().map(orders1 -> {
            OrderVO vo = new OrderVO();
            BeanUtils.copyProperties(orders1, vo);
            return vo;
        }).toList();
        List<OrderDetail> orderDetailList = orderDetailMapper.queryAll();
        orderVOS.forEach(orderVO -> {
            List<OrderDetail> list = orderDetailList.stream().filter(orderDetail -> orderDetail.getOrderId() == orderVO.getId()).toList();
            orderVO.setOrderDetailList(list);

        });
        return new PageResult(orders.getTotal(), orderVOS);
    }

    /**
     * 查看订单详情
     *
     * @param orderId
     * @return
     */
    @Override
    public OrderVO queryOrderDetail(Long orderId) {
        Orders orders = orderMapper.queryOrderDetail(orderId);
        OrderVO vo = new OrderVO();
        BeanUtils.copyProperties(orders, vo);
        // 查询订单明细表
        List<OrderDetail> orderDetailList = orderDetailMapper.queryDishOrSetmealByOrderId(orderId);
        vo.setOrderDetailList(orderDetailList);
        return vo;
    }


    /**
     * 取消订单
     *
     * @param
     */
    @Override
    public void cancelOrder(OrdersCancelDTO dto) {
        // 根据订单id查询订单是否为待支付或者待接单
        Orders orders = orderMapper.queryById(dto.getId());
        if (orders == null) {
            log.info("未查询到订单");
            return;
        }
        Integer status = orders.getStatus();
        if (status != 1 && status != 2) {
            throw new BaseException("该状态下无法直接取消,请联系商家");
        }
        log.info("处于待支付或待接单状态,可以直接退款");
        orders.setStatus(Orders.CANCELLED_ORDER);
        if (dto.getCancelReason() == null) {
            orders.setCancelReason("用户主动退款");
        } else {
            orders.setCancelReason(dto.getCancelReason());
        }
        orders.setCancelTime(LocalDateTime.now());
        orderMapper.modifyOrderStatus(orders);
    }


}
